#include "object_dir.h"
#include "object.h"
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "util.h"
#include <assert.h>

#define OBJECT_DIR_SIZE 100000


typedef struct {
  char object_name[ID_STRING_LENGTH];
  int disk;
  int cloud;
} odirent; 

static odirent *object_dir;
static int count;
pthread_mutex_t count_mut;

void dump_object_dir () {

  int i;
  debug ("=========================\n");
  for (i=0; i<count; i++) {
    odirent *t = object_dir+i;
    debug ("%s\t%d\t%d\n", t->object_name, t->disk, t->cloud);
  }

}

/* 
  Let's just start with a big list.
  The implementation should be changed to a trie or something similar
  but that can be done later without changing anything else.
*/

void init_object_dir() {
  object_dir = malloc (sizeof (odirent)* OBJECT_DIR_SIZE);
  count = 0; 
  pthread_mutex_init (&count_mut, NULL);
}

void add_to_object_dir (const char *object_name) { 

  /* First check if object already exists. If yes, we just return */

  int i;
  for (i=0; i<count; i++) {
    odirent *t = object_dir + i;
    if (strcmp (object_name, t->object_name) == 0) 
      return;
  }

  pthread_mutex_lock (&count_mut);
  if (count < OBJECT_DIR_SIZE-1) {
    odirent *t = object_dir+count;
    memcpy (t->object_name, object_name, ID_STRING_LENGTH);
    t->disk = 0;
    t->cloud = 0;
    count++;
  }
  pthread_mutex_unlock (&count_mut);

}

/* If -1, don't touch. If 0 or 1, set appropriately */
void set_field (const char *object_name, int disk, int cloud) {

  int i;
  for (i=0; i<count; i++) {
    odirent *t = object_dir + i;
    if (strcmp (object_name, t->object_name) == 0) {
      /* Found */

      if (disk != -1)
        t->disk = disk;
      if (cloud != -1)
        t->cloud = cloud;

      return;
    }
  }
  assert (0);
}


void set_disk_field (const char *object_name, int disk) {
  set_field (object_name, disk, -1);
}
void set_cloud_field (const char *object_name, int cloud) {
  set_field (object_name, -1, cloud);
}

void get_field (const char *object_name, int *disk, int *cloud) {

  int i;
  for (i=0; i<count; i++) {
    odirent *t = object_dir + i;
    if (strcmp (object_name, t->object_name) == 0) {
      /* Found */
      *disk = t->disk;
      *cloud = t->cloud;
      return;
    }
  }
}

int get_disk_field (const char *object_name) {
  int disk, cloud;
  get_field (object_name, &disk, &cloud);
  return disk;
}

int get_cloud_field (const char *object_name) {
  int disk, cloud;
  get_field (object_name, &disk, &cloud);
  return cloud;
}


int prefix_search (const char *prefix, int max_length, char *buf) {

  int prefix_len = strlen (prefix);
  int i;
  int ctr=0;
  for (i=0; i<count; i++) {
    odirent *t = object_dir + i;
    if (strncmp (prefix, t->object_name, prefix_len) == 0) {
      memcpy (buf + (ID_STRING_LENGTH*ctr), t->object_name, ID_STRING_LENGTH);
      ctr++;
      if (ctr*ID_STRING_LENGTH == max_length)
        return ctr;
    }
  }
  return ctr;
}

